package com.simon.study.algorithm.tree;

import java.util.Objects;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * <p>
 *
 * @author simon
 * @date 2022/8/21 4:47 下午
 */
@Getter
@Setter
@NoArgsConstructor @Accessors(chain = true)
public class TNode extends Node {

    TNode parent;

    TNode left;
    TNode right;

    public TNode(Integer data) {
        this.data = data;
    }

    public String toString(){
        return "TN:" + (Objects.isNull(data) ? "nil" : data.toString())
                + "(" + sdata(left) + "," + sdata(right) + ")"
                ;
    }

    public static String sdata(TNode node){
        if(node == null){ return "nil"; }
        if(node.data == null){ return "TN:nil"; }
        return node.data.toString();
    }


    public static String rbdata(RBNode node){
        if(node == null){ return "b-" + "nil"; }

        String prefix = node.color == 0 ? "b-" : "r-";

        if(node.data == null){ return "RB:" + prefix + "nil"; }

        return prefix + node.data.toString();
    }

    @Getter @Setter
    @NoArgsConstructor @Accessors(chain = true)
    public static class RBNode extends TNode{
        public static final int BLACK = 0;
        public static final int   RED = 1;
        /** 0 black, 1 red */
        int     color;

        public RBNode(Integer data) {
            super(data);
        }

        public RBNode(Integer data, int color) {
            super(data);
            this.color = color;
        }

        public RBNode parent(){
            return (RBNode) this.parent;
        }

        public RBNode grandparent(){
            if(parent != null){ return (RBNode) parent.parent; }
            return null;
        }

        public RBNode uncle(){
            RBNode grand = grandparent();
            if(Objects.isNull(grand)){ return null; }
            if(parent == grand.left){  return (RBNode) grand.right; }
            if(parent == grand.right){ return (RBNode) grand.left; }
            return null;
        }

        public RBNode sibling(){
            if(parent != null){
                return (RBNode) (this == parent.left ? parent.right : parent.left);
            }
            return null;
        }

        public String toString(){
            String prefix = color == 0 ? "b-" : "r-";
            return "RB:" + prefix + (Objects.isNull(data) ? "nil" : data.toString())
                    + "(" + rbdata((RBNode) left) + "," + rbdata((RBNode) right) + ")"
            ;
        }
    }


    @NoArgsConstructor
    @Setter @Getter @Accessors(chain = true)
    public static class HNode extends TNode{
        Integer weight;

        HNode left;
        HNode right;


        public HNode(Integer weight) {
            this(weight, weight);
        }

        public HNode(Integer data, Integer weight) {
            super(data);
            this.weight = weight;
        }

        public String toString(){
            return "HN:" + (Objects.isNull(weight) ? "nil" : weight.toString())
                    + "(" + sweight(left) + ", " + sweight(right) + ")";
        }



        public static String sweight(HNode node){
            if(node == null){ return "nil"; }
            else if( node.weight == null ){ return "HN:nil"; }
            else{
                return node.weight.toString();
            }
        }
    }
}
